package conf2.ui;

import conf2.model.EActor.Side;
import conf2.model.ETerritory;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

public class MainPanel extends JPanel
{

    private BufferedImage bgImage = Images.get(Images.Which.TABLE);
    private SwingWorker<Void, Void> animator = null;
    private String centerMessage = "";
    private MsgPanel centerMsgPanel = new MsgPanel();
    private List<ETerritory> highlightedRegions = null;

    public MainPanel()
    {
        setSize(800, 600);
        setPreferredSize(getSize());
        setLayout(null);

        add(centerMsgPanel);
    }

    BufferedImage getBackgroundImage()
    {
        return bgImage;
    }

    void hideBoard()
    {
        bgImage = Images.get(Images.Which.TABLE);
        repaint();
    }

    void highlightRegions(List<ETerritory> validMoves)
    {
        highlightedRegions = validMoves;
        repaint();
    }

    void showBoard(Side homeSide)
    {
        RegionBounds.setHomeSide(homeSide);
        bgImage = makeBGImage();
        repaint();
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        Rectangle r = g.getClipBounds();
        Image subImg = bgImage.getSubimage(r.x, r.y, r.width, r.height);
        g.drawImage(subImg, r.x, r.y, null);

        if (highlightedRegions != null) {
            g.setColor(new Color(0, 255, 0, 168));
            for (ETerritory et : highlightedRegions) {
                Polygon p = RegionBounds.get(et);
                g.fillPolygon(p);
            }
        }
    }

    private BufferedImage makeBGImage()
    {

        BufferedImage mapImage = new BufferedImage(800, 600, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = (Graphics2D) mapImage.getGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        g.setFont(FontSet.getRegionName());
        Image tableBGImage = Images.get(Images.Which.TABLE);
        g.drawImage(tableBGImage, 0, 0, null);

        for (ETerritory et : ETerritory.values()) {
            Color bg = ColorSet.getRegionBg(et);
            Polygon p = RegionBounds.get(et);
            g.setColor(bg);
            g.fillPolygon(p);

            // Region name string.
            String text = conf2.text.Regions.getMapName(et);
            Rectangle2D bounds = g.getFontMetrics().getStringBounds(text, g);
            Point c = RegionBounds.getCenterPoint(et);
            int x = c.x - (int) bounds.getWidth() / 2;
            int y = c.y + (int) bounds.getHeight() / 2;
            g.setColor(ColorSet.contrastingColor(g.getColor()));
            g.drawString(text, x, y);

            g.setColor(Color.BLACK);
            g.drawPolygon(p);
        }

        // arrows and shit
        Stroke savedStroke = g.getStroke();
        g.setStroke(new BasicStroke(2.5f));
        g.setColor(Color.GREEN);

        boolean lightDown = (RegionBounds.getHomeSide() == Side.LIGHT);
        if (lightDown) {
            // Moria arrow
            g.drawPolyline(
                    new int[]{330, 320, 342, 320},
                    new int[]{350, 310, 300, 253},
                    4);
            g.fillPolygon(
                    new int[]{320, 333, 315},
                    new int[]{250, 259, 265},
                    3);
            // Mirkwood -> Fangorn
            g.drawLine(215, 200, 235, 200);
            g.fillPolygon(
                    new int[]{235, 235, 245},
                    new int[]{193, 207, 200},
                    3);

            // Fangorn -> Rohan
            g.drawLine(365, 200, 385, 200);
            g.fillPolygon(
                    new int[]{385, 385, 395},
                    new int[]{193, 207, 200},
                    3);
        } else {
            // Same coordinates as above, but mirrored in the vertical line
            // x = 300.
            // Moria arrow
            g.drawPolyline(new int[]{270, 280, 258, 280},
                    new int[]{250, 290, 300, 347}, 4);
            g.fillPolygon(
                    new int[]{281, 268, 286},
                    new int[]{350, 341, 335},
                    3);
            // Mirkwood -> Fangorn
            g.drawLine(385, 400, 365, 400);
            g.fillPolygon(
                    new int[]{365, 365, 355},
                    new int[]{407, 393, 400},
                    3);

            // Fangorn -> Rohan
            g.drawLine(235, 400, 215, 400);
            g.fillPolygon(
                    new int[]{215, 215, 205},
                    new int[]{407, 393, 400},
                    3);
        }
        g.setStroke(savedStroke);

        return mapImage;
    }

    void setCenterMessage(String text)
    {
        centerMessage = text;
        System.out.println("Setting center message to: " + text);
    }

    void setCenterMessageVisible(boolean b)
    {
        centerMsgPanel.setVisible(b);
        setComponentZOrder(centerMsgPanel, 0);

        StackTraceElement e = new Throwable().getStackTrace()[2];
        if (b) {
            System.out.println("Showing message: " + centerMessage);
            System.out.println("  (called from " + e.getClassName() + ":" + e.getMethodName() + ")");
            startCenterMessageAnimation();
        } else {
            System.out.println("Hiding message: " + centerMessage);
            System.out.println("  (called from " + e.getClassName() + ":" + e.getMethodName() + ")");
            stopCenterMessageAnimation();
        }
    }

    private void startCenterMessageAnimation()
    {
        final String msg = centerMessage;
        animator = new SwingWorker<Void, Void>()
        {

            @Override
            protected Void doInBackground() throws Exception
            {

                final int len = msg.length();
                int p = len;
                int fp, lp;

                StringBuffer sb = new StringBuffer(len);

                fp = 0;
                lp = len - p + 1;
                while (true) {
                    String subMsg = msg.substring(fp, lp);

                    if (p > 0) {
                        for (int i = 0; i < p; i++) {
                            sb.append(' ');
                        }
                        sb.append(subMsg);
                    } else {
                        sb.append(subMsg);
                        for (int i = -1; i <= -p; i++) {
                            sb.append(' ');
                        }
                    }

                    p--;

                    if (p > 0) {
                        lp = len - p + 1;
                    } else {
                        fp++;
                    }

                    if (p == -len) {
                        p = len;
                        fp = 0;
                        lp = len - p + 1;
                    }

                    centerMsgPanel.setText(sb.toString());
                    sb.delete(0, sb.length());
                    Thread.sleep(150);
                }
            }
        };
        animator.execute();
    }

    private void stopCenterMessageAnimation()
    {
        if (animator != null) {
            animator.cancel(true);
            animator = null;
        }
    }

    private class MsgPanel extends JPanel
    {

        private Color bg = new Color(255, 255, 255, 127);
        private Font font = new Font(Font.MONOSPACED, Font.BOLD, 14);
        private String text = "";

        public MsgPanel()
        {
            setLayout(new FlowLayout(FlowLayout.CENTER));
            setBorder(BorderFactory.createLineBorder(Color.BLACK));
            setOpaque(false);
            setVisible(false);
        }

        public void setText(String s)
        {
            text = s;
            FontMetrics fm = getGraphics().getFontMetrics(font);
            setSize(Math.min(250, fm.stringWidth(s)), fm.getHeight() + 5);
            setLocation(299 - getWidth() / 2,
                    299 - getHeight() / 2);
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g)
        {
            g.setColor(bg);
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setFont(font);
            FontMetrics fm = g.getFontMetrics();
            int strw = fm.stringWidth(text);
            int strh = fm.getHeight();

            int x = (getWidth() - strw) / 2;
            int y = strh / 2 + fm.getDescent() + 2;
            g.setColor(Color.BLACK);
            g.drawString(text, x + 1, y + 1);
            g.setColor(Color.WHITE);
            g.drawString(text, x, y);
            super.paintComponent(g);
        }
    }
}
